#![no_std]
#![no_main]
#![feature(lang_items)]
#![feature(default_alloc_error_handler)]

extern crate alloc;

use alloc::string::String;
use api::gslb::get_servers;
use embed_std::thread::sleep_ms;
use embed_std::util::copy_cstr;
use embed_std::{errorln, infoln};
use sdk::SdkOptions;

// #[panic_handler]
// fn handle_panic(info: &PanicInfo) -> ! {
//     errorln!("panic: {}", info);
//     loop{}
// }

// #[lang = "eh_personality"]
// #[no_mangle]
// pub extern fn rust_eh_personality() {
//     errorln!("eh_personality");
// }

// #[no_mangle]
// pub extern fn _Unwind_Resume() {
//
// }

#[allow(dead_code)]
fn test_condvar() {
    use core::time::Duration;
    use embed_std::sync::arc::Arc;
    use embed_std::sync::condvar::Condvar;
    use embed_std::thread::spawn;

    infoln!("test condvar");
    let cond = Arc::new(Condvar::new(0u8));
    const NUM: usize = 10;
    for i in 0..NUM {
        let cond1 = cond.clone();
        let _ = spawn(move || {
            infoln!("[{}] thread waiting...", i);
            let _ = cond1.wait_timeout(Duration::from_secs(1000));
            infoln!("[{}] thread quit", i);
        });
    }
    sleep_ms(3000);
    cond.notify_all();
    // for i in 0..NUM {
    //     infoln!("[{}] notify one", i);
    //     cond.notify_one();
    //     sleep_ms(500);
    // }
}

#[no_mangle]
pub extern "C" fn main(argc: i32, argv: *mut *mut i8) -> i32 {
    // use embed_std::log::set_log_level;
    // set_log_level(1);
    // test_condvar();
    let args = unsafe { core::slice::from_raw_parts(argv as *const *const i8, argc as usize) };
    unsafe {
        libc::printf(
            "usage %s: [<region> [<product_code> <device_uid> <secret]]\n\0".as_ptr() as *const i8,
            args[0],
        );
        libc::printf("    region: 0(local) 1(test) 2(bl)\n\0".as_ptr() as *const i8);
    }
    let regions: [&str; 3] = ["127.0.0.1", "192.168.1.129", "gslb.iot.zediel.cn"];
    let region = if argc >= 2 {
        unsafe { libc::atoi(args[1]) }
    } else {
        0
    };
    if region >= regions.len() as i32 || region < 0 {
        errorln!("invalid region {}", region);
        return 1;
    }
    let param = sdk::PersisParams::get();
    if argc >= 5 {
        copy_cstr(args[2], &mut param.product_code);
        copy_cstr(args[3], &mut param.device_uid);
        copy_cstr(args[4], &mut param.secret);
    }
    let servers = get_servers(
        regions[region as usize],
        param.product_code_str(),
        param.device_uid_str(),
    )
    .expect("get servers from gslb failed");
    infoln!("servers {:?}", servers);

    let mut opts = SdkOptions::new();
    opts.ip = String::from(regions[region as usize]);
    infoln!("region {} ip {}", region, opts.ip);
    sdk::rust_init_iot_sdk(opts);
    infoln!("do idle loop");
    loop {
        sleep_ms(5000);
    }
}
